package com.app.brilliant.game.service.impl;
import com.app.brilliant.common.enums.StateEnum;
import com.app.brilliant.game.bean.WechatQrCode;
import com.app.brilliant.game.config.WechatConfig;
import com.app.brilliant.game.response.WechatQrCodeResponse;
import com.app.brilliant.game.response.WechatQrStatusResponse;
import com.app.brilliant.game.service.WechatQrCodeService;
import com.app.brilliant.shiro.cache.LoginRedisService;
import com.app.brilliant.shiro.convert.DevUserConvert;
import com.app.brilliant.shiro.jwt.JwtProperties;
import com.app.brilliant.shiro.jwt.JwtToken;
import com.app.brilliant.shiro.util.JwtUtil;
import com.app.brilliant.shiro.util.LoginUtil;
import com.app.brilliant.shiro.util.SaltUtil;
import com.app.brilliant.shiro.vo.dev.LoginDevUserVo;
import com.app.brilliant.sys.bean.DevUser;
import com.app.brilliant.sys.service.DevUserService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.io.ByteArrayOutputStream;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 微信二维码服务实现类
 */
@Slf4j
@Service
public class WechatQrCodeServiceImpl implements WechatQrCodeService {

    @Autowired
    private WechatConfig wechatConfig;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private DevUserService devUserService;

    @Autowired
    private LoginRedisService loginRedisService;

    @Autowired
    private JwtProperties jwtProperties;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    private static final String QR_CODE_KEY_PREFIX = "wechat:qr:";
    private static final String QR_CODE_STATUS_PENDING = "PENDING";
    private static final String QR_CODE_STATUS_SCANNED = "SCANNED";
    private static final String QR_CODE_STATUS_CONFIRMED = "CONFIRMED";
    private static final String QR_CODE_STATUS_EXPIRED = "EXPIRED";

    @Override
    public WechatQrCodeResponse generateQrCode() {
        try {
            // 生成二维码ID
            String qrId = UUID.randomUUID().toString().replace("-", "");

            // 构建微信授权URL
            String authUrl = buildAuthUrl(qrId);

            // 生成二维码
            String qrCodeBase64 = generateQrCodeBase64(authUrl);

            // 创建二维码信息
            WechatQrCode qrCode = new WechatQrCode();
            qrCode.setQrId(qrId);
            qrCode.setStatus(QR_CODE_STATUS_PENDING);
            qrCode.setCreateTime(LocalDateTime.now());
            qrCode.setExpireTime(LocalDateTime.now().plusSeconds(wechatConfig.getQrExpireSeconds()));

            // 存储到Redis
            String redisKey = QR_CODE_KEY_PREFIX + qrId;
            redisTemplate.opsForValue().set(redisKey, qrCode, wechatConfig.getQrExpireSeconds(), TimeUnit.SECONDS);

            // 构建响应
            WechatQrCodeResponse response = new WechatQrCodeResponse();
            response.setQrCodeId(qrId);
            response.setQrCodeUrl(qrCodeBase64);
            response.setStatus(QR_CODE_STATUS_PENDING);
            response.setExpireSeconds((long) wechatConfig.getQrExpireSeconds());

            log.info("生成微信二维码成功，qrId: {}", qrId);
            return response;

        } catch (Exception e) {
            log.error("生成微信二维码失败", e);
            throw new RuntimeException("生成二维码失败");
        }
    }

    @Override
    public WechatQrStatusResponse checkQrStatus(String qrId) {
        try {
            WechatQrCode qrCode = getQrCode(qrId);
            if (qrCode == null) {
                return createExpiredResponse();
            }

            // 检查是否过期
            if (LocalDateTime.now().isAfter(qrCode.getExpireTime())) {
                updateQrStatus(qrId, QR_CODE_STATUS_EXPIRED, null);
                return createExpiredResponse();
            }

            WechatQrStatusResponse response = new WechatQrStatusResponse();
            response.setStatus(qrCode.getStatus());

            // 如果已确认，返回用户信息和token
            if (QR_CODE_STATUS_CONFIRMED.equals(qrCode.getStatus())) {
                WechatQrStatusResponse.WechatUserInfo userInfo = new WechatQrStatusResponse.WechatUserInfo();
                userInfo.setOpenId(qrCode.getOpenId());
                userInfo.setUnionId(qrCode.getUnionId());
                userInfo.setNickName(qrCode.getNickName());
                userInfo.setAvatarUrl(qrCode.getAvatarUrl());
                response.setUserInfo(userInfo);
                response.setToken(qrCode.getCode()); // 返回token
            }

            return response;

        } catch (Exception e) {
            log.error("检查二维码状态失败，qrId: {}", qrId, e);
            return createExpiredResponse();
        }
    }

    @Override
    public void handleCallback(String code, String state) {
        try {
            log.info("收到微信回调，code: {}, state: {}", code, state);

            if (code == null || state == null) {
                log.error("微信回调参数不完整");
                return;
            }

            // 获取二维码信息
            WechatQrCode qrCode = getQrCode(state);
            if (qrCode == null) {
                log.error("二维码不存在或已过期，qrId: {}", state);
                return;
            }

            // 检查是否过期
            if (LocalDateTime.now().isAfter(qrCode.getExpireTime())) {
                updateQrStatus(state, QR_CODE_STATUS_EXPIRED, null);
                return;
            }

            // 更新状态为已扫码
            updateQrStatus(state, QR_CODE_STATUS_SCANNED, null);

            // 通过code获取用户信息
            WechatQrStatusResponse.WechatUserInfo userInfo = getUserInfoByCode(code);
            if (userInfo == null) {
                log.error("获取用户信息失败");
                return;
            }

            DevUser devUser = devUserService.getDevUserBySalt(state);
            if (devUser != null) {
                devUser.setNickName(userInfo.getNickName());
                devUser.setAvatarUrl(userInfo.getAvatarUrl());
                devUser.setOpenId(userInfo.getOpenId());
                devUser.setUnionId(userInfo.getUnionId());
                devUserService.updateById(devUser);
            }else{
                // 保存用户信息到wxUser表（参考wxUserService.loginWx方法）
                DevUser wxUser = saveUserInfo(userInfo);
                // 生成用户JWT token（参考wxUserService.loginWx方法）
                String token = generateUserToken(wxUser);
                // 更新二维码状态为已确认
                qrCode.setCode(token); // 存储token供客户端获取
            }
            qrCode.setStatus(QR_CODE_STATUS_CONFIRMED);
            qrCode.setOpenId(userInfo.getOpenId());
            qrCode.setUnionId(userInfo.getUnionId());
            qrCode.setNickName(userInfo.getNickName());
            qrCode.setAvatarUrl(userInfo.getAvatarUrl());
            qrCode.setConfirmTime(LocalDateTime.now());
            // 保存到Redis
            String redisKey = QR_CODE_KEY_PREFIX + state;
            redisTemplate.opsForValue().set(redisKey, qrCode, wechatConfig.getQrExpireSeconds(), TimeUnit.SECONDS);

            log.info("微信登录成功，qrId: {}, openId: {}, token已生成并保存到Redis", state, userInfo.getOpenId());

        } catch (Exception e) {
            log.error("处理微信回调失败", e);
        }
    }

    @Override
    public WechatQrCode getQrCode(String qrId) {
        String redisKey = QR_CODE_KEY_PREFIX + qrId;
        return (WechatQrCode) redisTemplate.opsForValue().get(redisKey);
    }

    @Override
    public void updateQrStatus(String qrId, String status, WechatQrStatusResponse.WechatUserInfo userInfo) {
        WechatQrCode qrCode = getQrCode(qrId);
        if (qrCode != null) {
            qrCode.setStatus(status);
            if (QR_CODE_STATUS_SCANNED.equals(status)) {
                qrCode.setScanTime(LocalDateTime.now());
            }
            if (userInfo != null) {
                qrCode.setOpenId(userInfo.getOpenId());
                qrCode.setUnionId(userInfo.getUnionId());
                qrCode.setNickName(userInfo.getNickName());
                qrCode.setAvatarUrl(userInfo.getAvatarUrl());
            }

            String redisKey = QR_CODE_KEY_PREFIX + qrId;
            redisTemplate.opsForValue().set(redisKey, qrCode, wechatConfig.getQrExpireSeconds(), TimeUnit.SECONDS);
        }
    }

    /**
     * 构建微信授权URL
     */
    private String buildAuthUrl(String qrId) {
        return String.format(
                "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_userinfo&state=%s#wechat_redirect",
                wechatConfig.getAppId(),
                wechatConfig.getRedirectUri(),
                qrId);
    }

    /**
     * 生成二维码base64数据
     */
    private String generateQrCodeBase64(String content) {
        try {
            // 使用ZXing生成二维码
            com.google.zxing.BarcodeFormat format = com.google.zxing.BarcodeFormat.QR_CODE;
            com.google.zxing.Writer writer = new com.google.zxing.qrcode.QRCodeWriter();
            com.google.zxing.common.BitMatrix bitMatrix = writer.encode(content, format, 200, 200);

            // 转换为图片
            java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(200, 200,
                    java.awt.image.BufferedImage.TYPE_INT_RGB);
            for (int x = 0; x < 200; x++) {
                for (int y = 0; y < 200; y++) {
                    image.setRGB(x, y,
                            bitMatrix.get(x, y) ? java.awt.Color.BLACK.getRGB() : java.awt.Color.WHITE.getRGB());
                }
            }

            // 转换为base64
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            javax.imageio.ImageIO.write(image, "PNG", baos);
            byte[] imageBytes = baos.toByteArray();

            return "data:image/png;base64," + java.util.Base64.getEncoder().encodeToString(imageBytes);

        } catch (Exception e) {
            log.error("生成二维码失败", e);
            throw new RuntimeException("生成二维码失败");
        }
    }

    @Override
    public WechatQrCodeResponse generateBindQrCode(Long devId) {
        try {

            // 生成用户token
            String token = devUserService.getById(devId).getSalt();

            // 构建微信授权URL，将token作为state参数
            String authUrl = buildAuthUrl(token);

            // 生成二维码
            String qrCodeBase64 = generateQrCodeBase64(authUrl);

            // 创建二维码信息
            WechatQrCode qrCode = new WechatQrCode();
            qrCode.setQrId(token);
            qrCode.setStatus(QR_CODE_STATUS_PENDING);
            qrCode.setCreateTime(LocalDateTime.now());
            qrCode.setExpireTime(LocalDateTime.now().plusSeconds(wechatConfig.getQrExpireSeconds()));

            // 存储到Redis
            String redisKey = QR_CODE_KEY_PREFIX + token;
            redisTemplate.opsForValue().set(redisKey, qrCode, wechatConfig.getQrExpireSeconds(), TimeUnit.SECONDS);

            // 构建响应
            WechatQrCodeResponse response = new WechatQrCodeResponse();
            response.setQrCodeId(token);
            response.setQrCodeUrl(qrCodeBase64);
            response.setStatus(QR_CODE_STATUS_PENDING);

            log.info("生成绑定微信二维码成功，qrId: {}, token: {}",  token);
            return response;

        } catch (Exception e) {
            log.error("生成绑定微信二维码失败", e);
            throw new RuntimeException("生成绑定二维码失败");
        }
    }

    /**
     * 通过code获取用户信息
     */
    private WechatQrStatusResponse.WechatUserInfo getUserInfoByCode(String code) {
        try {
            // 1. 通过code获取access_token
            String tokenUrl = String.format(
                    "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code",
                    wechatConfig.getAppId(),
                    wechatConfig.getAppSecret(),
                    code);

            String tokenResponse = restTemplate.getForObject(tokenUrl, String.class);
            com.fasterxml.jackson.databind.JsonNode tokenNode = objectMapper.readTree(tokenResponse);

            if (tokenNode.has("errcode")) {
                log.error("获取access_token失败: {}", tokenResponse);
                return null;
            }

            String accessToken = tokenNode.get("access_token").asText();
            String openId = tokenNode.get("openid").asText();
            String unionId = tokenNode.has("unionid") ? tokenNode.get("unionid").asText() : null;

            // 2. 通过access_token获取用户信息
            String userInfoUrl = String.format(
                    "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN",
                    accessToken,
                    openId);

            String userInfoResponse = restTemplate.getForObject(userInfoUrl, String.class);
            com.fasterxml.jackson.databind.JsonNode userNode = objectMapper.readTree(userInfoResponse);

            if (userNode.has("errcode")) {
                log.error("获取用户信息失败: {}", userInfoResponse);
                return null;
            }

            WechatQrStatusResponse.WechatUserInfo userInfo = new WechatQrStatusResponse.WechatUserInfo();
            userInfo.setOpenId(openId);
            userInfo.setUnionId(unionId);
            userInfo.setNickName(userNode.get("nickname").asText());
            userInfo.setAvatarUrl(userNode.get("headimgurl").asText());

            return userInfo;

        } catch (Exception e) {
            log.error("获取用户信息失败", e);
            return null;
        }
    }

    /**
     * 保存用户信息到wxUser表（参考wxUserService.loginWx方法）
     */
    private DevUser saveUserInfo(WechatQrStatusResponse.WechatUserInfo userInfo) {
        try {
            // 查找或创建用户（参考wxUserService.loginWx的逻辑）
            DevUser wxUser = devUserService.getByOpenId(userInfo.getOpenId());
            if (wxUser == null) {
                // 创建新用户
                wxUser = new DevUser();
                wxUser.setOpenId(userInfo.getOpenId());
                wxUser.setUnionId(userInfo.getUnionId());
                wxUser.setNickName(userInfo.getNickName());
                wxUser.setAvatarUrl(userInfo.getAvatarUrl());
                wxUser.setCreateTime(new java.util.Date());
                devUserService.save(wxUser);
                log.info("创建新微信用户，openId: {}", userInfo.getOpenId());
            } else {
                // 更新用户信息
                wxUser.setNickName(userInfo.getNickName());
                wxUser.setAvatarUrl(userInfo.getAvatarUrl());
                devUserService.updateById(wxUser);
                log.info("更新微信用户信息，openId: {}", userInfo.getOpenId());
            }
            return wxUser;
        } catch (Exception e) {
            log.error("保存用户信息失败", e);
            throw new RuntimeException("保存用户信息失败");
        }
    }

    /**
     * 生成用户JWT token（参考wxUserService.loginWx方法）
     */
    private String generateUserToken(DevUser wxUser) {
        try {
            LoginDevUserVo loginAppUserRedisVo = DevUserConvert.INSTANCE.devUserToLoginDevUserVo(wxUser);
            // 获取数据库中保存的盐值
            String newSalt = SaltUtil.getSalt(wxUser.getSalt(), jwtProperties);
            // 生成token字符串并返回
            Long expireSecond = jwtProperties.getExpireSecond();
            String token = JwtUtil.generateToken("Develop", wxUser.getId() + "", newSalt, Duration.ofSeconds(expireSecond));
            // 创建AuthenticationToken
            JwtToken jwtToken = JwtToken.build("Develop", token, wxUser.getId() + "", newSalt, expireSecond);
            loginRedisService.cacheLoginInfo(jwtToken, loginAppUserRedisVo);
            return token;
        } catch (Exception e) {
            log.error("生成用户token失败", e);
            throw new RuntimeException("生成token失败");
        }
    }

    /**
     * 创建过期响应
     */
    private WechatQrStatusResponse createExpiredResponse() {
        WechatQrStatusResponse response = new WechatQrStatusResponse();
        response.setStatus(QR_CODE_STATUS_EXPIRED);
        return response;
    }
}